package simplevideochat.communication
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	
	import simplevideochat.configuration.ConfigurationFactory;

	/**
	 * Класс для управления комнатами сервером
	 */
	public class ServerRoomManager implements IRoomManager
	{		
		private var socket:NodeJSSocket;
		private var currentRoom:IRoom;
		private var eventDispatcher:EventDispatcher;
		
		private var host:String = "127.0.0.1";
		private var port:uint = 8123;
		
		private var configurationFactory:ConfigurationFactory;
		
		/**
		 * Конструктор класса управления комнатами сервером
		 */
		public function ServerRoomManager(host:String = "", port:uint = 0)
		{
			this.host = host;
			this.port = port;
			socket = new NodeJSSocket(host, port);
			eventDispatcher = new EventDispatcher();
			
			configurationFactory = new ConfigurationFactory();
		}
		
		/**
		 * Создать новую комнату
		 */
		public function createNewRoom():void
		{
			currentRoom = configurationFactory.createRoom();
			socket.addEventListener(NodeJSSocketEvent.GET_MESSAGE, getMessageHandler);
			socket.addEventListener(NodeJSSocketEvent.ERROR, getError);
			if (!socket.connected) {
				socket.connect(host, port);
			}
			socket.sendMessage("create_room");
		}
		
		/**
		 * Присоединиться к существующей комнате
		 * @param	roomID	Идентификатор комнаты
		 * @return	Результат, удалось ли подключиться
		 */
		public function joinToRoom(roomID:String):Boolean
		{
			if (roomID.length > 0) {
				currentRoom = configurationFactory.createRoom(roomID);
				eventDispatcher.dispatchEvent(new ServerRoomManagerEvent(ServerRoomManagerEvent.ROOM_CREATED, currentRoom));
				return true;
			}
			return false;
		}
		
		/**
		 * Удалить комнату
		 * @param	room	Удаляемая комната
		 */
		public function removeRoom(room:IRoom):void
		{
			//TODO: implement function
		}
		
		/**
		 * Получить созданную комнату
		 * @return	Созданная комната либо null, если комната не создана
		 */
		public function getCreatedRoom():IRoom
		{
			return currentRoom;
		}
		
		/**
		 * Проверить, существует ли комната с заданным именем
		 * @param	roomName	Имя комнаты
		 * @return	Существует ли комната
		 */
		public function isRoomExists(roomName:String):Boolean
		{
			//TODO: implement function
			return false;
		}
		
		/**
		 * Добавить слушатель для события
		 * @param	type	Тип прослушиваемого события
		 * @param	listener	Функция - слушатель события
		 */
		public function addEventListener(type:String, listener:Function):void
		{
			eventDispatcher.addEventListener(type, listener);
		}
		
		/**
		 * Удалить слушателя для события с заданным типом
		 * @param	type	Тип прослушиваемого события
		 * @param	listener	Функция - слушатель события
		 */
		public function removeEventListener(type:String, listener:Function):void
		{
			eventDispatcher.removeEventListener(type, listener);
		}
		
		/**
		 * Обработчик события получения сообщения от сокета
		 * @param	event	Событие получения сообщения
		 */
		private function getMessageHandler(event:NodeJSSocketEvent):void
		{
			currentRoom.roomID = event.message;
			eventDispatcher.dispatchEvent(new ServerRoomManagerEvent(ServerRoomManagerEvent.ROOM_CREATED, currentRoom));
		}
		
		/**
		 * Обработчик события ошибки от сокета
		 * @param	event	Событие ошибки
		 */
		private function getError(event:NodeJSSocketEvent):void
		{
			trace("ServerRoomManager: get error from socket");
			//если сервер не может создать комнату, создаем общую для всех тестовую комнату
			currentRoom.roomID = "test";
			eventDispatcher.dispatchEvent(new ServerRoomManagerEvent(ServerRoomManagerEvent.ROOM_CREATED, currentRoom));
		}
	}
}

import adobe.utils.CustomActions;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.SecurityErrorEvent;
import flash.net.Socket;

/**
 * Класс сокета для соединения с сервером Nodejs
 */
class NodeJSSocket extends Socket
{
	
	private var isSendMessage:Boolean;
	private var message:String;
	
	/**
	 * Конструктор класса сокета для соединения с сервером
	 * @param	host	Адрес сервера
	 * @param	port	Порт сервера
	 */
	public function NodeJSSocket(host:String, port:int):void
	{
		super(host, port);
		initListeners();
		isSendMessage = false;
		message = null;
	}
	
	/**
	 * Инициализировать слушателей
	 */
	private function initListeners():void
	{
		addEventListener(Event.CONNECT, connectHandler);
		addEventListener(Event.CLOSE, closeHandler);
		addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
		addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
		addEventListener(ProgressEvent.SOCKET_DATA, readMessage);
	}
	
	/**
	 * Обработчик события подключения к серверу
	 * @param	event	Событие подключения
	 */
	private function connectHandler(event:Event):void
	{
		trace("Socket: connected");
		if (isSendMessage) {
			sendMessage(message);
		}
	}
	
	/**
	 * Обработчик события закрытия соединения с сервером
	 * @param	event	События закрытия соединения
	 */
	private function closeHandler(event:Event):void
	{
		//TODO implement this
	}
	
	/**
	 * Обработчик ошибок
	 * @param	event	Событие ошибки
	 */
	private function ioErrorHandler(event:IOErrorEvent):void
	{
		trace("ioErrorHandler: " + event);
		dispatchEvent(new NodeJSSocketEvent(NodeJSSocketEvent.ERROR, event.text));
	}
	
	/**
	 * Обработчик события ошибки безопасности
	 * @param	event	Событие ошибки безопасности
	 */
	private function securityErrorHandler(event:SecurityErrorEvent):void
	{
		trace("securityErrorHandler: " + event);
		dispatchEvent(new NodeJSSocketEvent(NodeJSSocketEvent.ERROR, event.text));
	}
	
	/**
	 * Отправить сообщение
	 * @param	message	Текст сообщения
	 */
	public function sendMessage(message:String):void
	{
		if (connected) {
			trace("Socket: send message");
			writeUTFBytes(message);
			flush();
		} else {
			isSendMessage = true;
			this.message = message;
			trace("Socket: user want to send message, but socket is not connected");
		}
	}
	
	/**
	 * Обработчик получения сообщения
	 * @param	event	Событие получения сообщения
	 */
	private function readMessage(event:ProgressEvent):void
	{
		var message:String = readUTFBytes(bytesAvailable);
		var msgEvent:NodeJSSocketEvent = new NodeJSSocketEvent(NodeJSSocketEvent.GET_MESSAGE, message);
		trace("Socket: read message");
		dispatchEvent(msgEvent);
		close();
	}
}

/**
 * Класс события сокета сервера на Nodejs
 */
class NodeJSSocketEvent extends Event
{
	/**
	 * Событие получения сообщения
	 */
	public static const GET_MESSAGE:String = "node_js_socket_event_get_message";
	
	/**
	 * Событие ошибки
	 */
	public static const ERROR:String = "node_js_socket_event_error";
	
	private var _message:String;
	
	/**
	 * Конструктор события сокета сервера
	 * @param	type	Тип события
	 * @param	message	Текс сообщения
	 */
	public function NodeJSSocketEvent(type:String, message:String = null):void
	{
		super(type, bubbles, cancelable);
		this.message = message;
	}
	
	/**
	 * Текст сообщения
	 */
	public function set message(value:String):void
	{
		_message = value;
	}
	
	public function get message():String
	{
		return _message;
		
	}
}